/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** *****************************************************************************************************
 * \file     Lin_Ip.c                                                                                   *
 * \brief    This file mainly implements the definition of register operation interface                 *
 *                                                                                                      *
 * <table>                                                                                              *
 * <tr><th>Date           <th>Version                                                                   *
 * <tr><td>2023/08/18     <td>1.0.0                                                                     *
 * </table>                                                                                             *
 *******************************************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

/********************************************************************************************************
 *                                      Include header files                                            *
 *******************************************************************************************************/
#include "Lin_Ip.h"
#if (LIN_SLAVE_MODE_USED == STD_ON)
#include "LinIf.h"
#endif /* LIN_SLAVE_MODE_USED */
#include "Mcal_MemLibc.h"
#include "SchM_Lin.h"

/********************************************************************************************************
 *                                         Macro definition                                             *
 *******************************************************************************************************/
/* lin err interrupt */
#define LIN_ERR_INT_STA     (LIN_INTR0_TXFUDF | LIN_INTR0_RXFUDF | \
                            LIN_INTR0_TXFOVF | LIN_INTR0_RXFOVF | \
                            LIN_INTR0_PARITYERR | LIN_INTR0_FRAMEERR | \
                            LIN_INTEN0_STARTERRE | LIN_INTR0_NOISEERR)
/* lin frame err interrupt */
#define LIN_FRAME_ERR_INT_STA     (LIN_INTR0_PARITYERR | LIN_INTR0_FRAMEERR | \
                                  LIN_INTEN0_STARTERRE | LIN_INTR0_NOISEERR)
/* lin fifo err interrupt */
#define LIN_TX_FIFO_ERR_INT_STA     (LIN_INTR0_TXFUDF | LIN_INTR0_TXFOVF)
#define LIN_RX_FIFO_ERR_INT_STA     (LIN_INTR0_RXFUDF | LIN_INTR0_RXFOVF)

/********************************************************************************************************
 *                                      Global variables                                                *
 *******************************************************************************************************/
extern Lin_HandlerType * const Lin_Handler[CPU_MAX_CORE_NUMBER];

/********************************************************************************************************
 *                                      internal fcuntion                                               *
 *******************************************************************************************************/
#define LIN_START_SEC_CODE_FAST
#include "Lin_MemMap.h"

/**
 * @brief Check channel error status.
 *
 * Check the channel error status based on the given node ID and interrupt status,
 * and perform corresponding actions.
 *
 * @param nodeId The node ID.
 * @param intSta The interrupt status.
 *
 * @return Returns TRUE if there is a channel error, FALSE otherwise.
 */
static boolean Lin_CheckChanErrsta(uint8 nodeId, uint32 intSta)
{
    boolean chanErr = FALSE;
    const Lin_Uart      *locNodeCfg;
    Lin_NodeDataType        *locNodeData;
    uint8 coreId = Lin_GetCoreId();

    /* Initialize local variables*/
    locNodeCfg  = &(Lin_Handler[coreId]->config->channels[nodeId]);
    locNodeData = &(Lin_Handler[coreId]->channelInfo[nodeId].nodeData);
    if (intSta & LIN_ERR_INT_STA)
    {
        /* update channel error status */
        chanErr = TRUE;
        /* frame err : reset module */
        if (intSta & LIN_FRAME_ERR_INT_STA)
        {
            Lin_HwRstMod(nodeId);
        }
        /* tx fifo err : reset tx fifo */
        if (intSta & LIN_TX_FIFO_ERR_INT_STA)
        {
            Lin_UartClrTxFifo(locNodeCfg);
        }
        /* rx fifo err : reset rx fifo */
        if (intSta & LIN_RX_FIFO_ERR_INT_STA)
        {
            Lin_UartClrRxFifo(locNodeCfg);
        }

        /* switch lin status */
        switch (locNodeData->framestate)
        {
        case LIN_FRAMERECEIVE:
            Lin_UartClrRxFifo(locNodeCfg);
            locNodeData->error   = LIN_FRAMIN_ERROR;
            Lin_Handler[coreId]->channelInfo[nodeId].ChannelState = LIN_RX_ERROR;

            if (locNodeCfg->dataPtr.mode == LIN_UART_SLAVE)
            {
                locNodeData->framestate   = LIN_FRAMEPENDING;
#if (LIN_SLAVE_MODE_USED == STD_ON)
                LinIf_LinErrorIndication(nodeId, LIN_ERR_INC_RESP);
#endif /* LIN_SLAVE_MODE_USED */
            }
            else
            {
                locNodeData->framestate   = LIN_FRAMERECEIVEERR;
            }
            break;
        case LIN_FRAMETRANSMIT:
            Lin_UartClrTxFifo(locNodeCfg);
            Lin_Handler[coreId]->channelInfo[nodeId].ChannelState = LIN_TX_ERROR;
            if (locNodeCfg->dataPtr.mode == LIN_UART_SLAVE)
            {
                locNodeData->framestate   = LIN_FRAMEPENDING;
#if (LIN_SLAVE_MODE_USED == STD_ON)
                LinIf_LinErrorIndication(nodeId, LIN_ERR_RESP_DATABIT);
#endif /* LIN_SLAVE_MODE_USED */
            }
            else
            {
                locNodeData->framestate   = LIN_FRAMETRANSMITERR;
            }
            break;
        case LIN_FRAMEPENDING:
#if (LIN_SLAVE_MODE_USED == STD_ON)
            if (intSta & LIN_INTR0_RXPIDERR || intSta & LIN_INTR0_RXPIDPASS)
            {
                LinIf_LinErrorIndication(nodeId, LIN_ERR_HEADER);
            }
#endif /* LIN_SLAVE_MODE_USED */
            break;
        default:
            if (locNodeCfg->dataPtr.mode == LIN_UART_SLAVE)
            {
                locNodeData->framestate   = LIN_FRAMEPENDING;
            }
            else
            {
                locNodeData->framestate   = LIN_FRAMEIDLE;
            }
            break;
        }
    }
    return chanErr;
}

/**
 * @brief LIN Wakeup Processing Function
 *
 * Handles LIN wakeup events based on the given node ID and interrupt status.
 *
 * @param nodeId The node ID.
 * @param intSta The interrupt status.
 */
static void Lin_WakeupProcess(uint8 nodeId, uint32 intSta)
{
    const Lin_Uart      *locNodeCfg;
    Lin_NodeDataType        *locNodeData;
    uint8 coreId = Lin_GetCoreId();

    /* Initialize local variables*/
    locNodeCfg  = &(Lin_Handler[coreId]->config->channels[nodeId]);
    locNodeData = &(Lin_Handler[coreId]->channelInfo[nodeId].nodeData);
    /* slave mode: rxbreak int is wakeup signal
        master mode: frameerr is wakeup signal */
    if (intSta & LIN_INTR0_RXBREAK || intSta & LIN_INTR0_FRAMEERR)
    {
        /* Get ready for sync break transmission */
        if (Lin_Handler[coreId]->wakeupSelfFlag[nodeId] == TRUE)
        {
            locNodeData->currentState = LIN_ACTIVE;
            Lin_Handler[coreId]->wakeupSelfFlag[nodeId] = FALSE;
        }
        if (locNodeCfg->dataPtr.mode == LIN_UART_SLAVE)
        {
            locNodeData->framestate   = LIN_FRAMEPENDING;

        }
        else
        {
            Lin_Handler[coreId]->sleepFlag[nodeId] = FALSE;
            locNodeData->framestate   = LIN_FRAMEIDLE;
        }
        Lin_Handler[coreId]->wakeupFlag[nodeId] = TRUE;
        Lin_UartRstMod(locNodeCfg);
    }
}

/**
 * @brief LIN Frame Reception Processing Function
 *
 * Processes LIN frame reception based on the given node ID and interrupt status.
 *
 * @param nodeId The node ID
 * @param intSta The interrupt status
 */
static void Lin_FrameRecieveProc(uint8 nodeId, uint32 intSta)
{
    const Lin_Uart      *locNodeCfg;
    Lin_NodeDataType        *locNodeData;
    uint8 coreId = Lin_GetCoreId();

    /* Initialize local variables*/
    locNodeCfg  = &(Lin_Handler[coreId]->config->channels[nodeId]);
    locNodeData = &(Lin_Handler[coreId]->channelInfo[nodeId].nodeData);
    /* check recieve frame checksum status */
    if (intSta & LIN_INTR0_RXCHKSUMPASS)
    {
        /* get frame data */
        Lin_UartGetChar(locNodeCfg, locNodeData->rxframe, locNodeData->dl);
        /* update channel status */
        Lin_Handler[coreId]->channelInfo[nodeId].ChannelState = LIN_RX_OK;

        if (locNodeCfg->dataPtr.mode == LIN_UART_SLAVE)
        {
            locNodeData->framestate   = LIN_FRAMEPENDING;
#if (LIN_SLAVE_MODE_USED == STD_ON)
            LinIf_RxIndication(nodeId, (locNodeData->rxframe));
#endif /* LIN_SLAVE_MODE_USED */
        }
        else
        {
            locNodeData->framestate   = LIN_FRAMEIDLE;
        }
    }
    else if (intSta & LIN_INTR0_RXCHKSUMERR)
    {
        /* get the wrong data */
        Lin_UartGetChar(locNodeCfg, locNodeData->rxframe, locNodeData->dl);
        /* update lin channel status */
        locNodeData->error   = LIN_CHKSUM_ERROR;
        Lin_Handler[coreId]->channelInfo[nodeId].ChannelState = LIN_RX_ERROR;

        if (locNodeCfg->dataPtr.mode == LIN_UART_SLAVE)
        {
            locNodeData->framestate   = LIN_FRAMEPENDING;
#if (LIN_SLAVE_MODE_USED == STD_ON)
            LinIf_LinErrorIndication(nodeId, LIN_ERR_RESP_CHKSUM);
#endif /* LIN_SLAVE_MODE_USED */
        }
        else
        {
            locNodeData->framestate   = LIN_FRAMECHECKSUMERR;
        }
    }
    else if (intSta & LIN_INTR0_APBCMDABORT)
    {
        /* clear uart fifo */
        Lin_UartClrRxFifo(locNodeCfg);
        /* update lin channel status */
        locNodeData->error   = LIN_FRAMIN_ERROR;
        Lin_Handler[coreId]->channelInfo[nodeId].ChannelState = LIN_RX_ERROR;
        if (locNodeCfg->dataPtr.mode == LIN_UART_SLAVE)
        {
            locNodeData->framestate   = LIN_FRAMEPENDING;
#if (LIN_SLAVE_MODE_USED == STD_ON)
            LinIf_LinErrorIndication(nodeId, LIN_ERR_INC_RESP);
#endif /* LIN_SLAVE_MODE_USED */
        }
        else
        {
            Lin_UartRstMod(locNodeCfg);
            locNodeData->framestate   = LIN_FRAMERECEIVEERR;

        }
    }
}

/**
 * @brief LIN Frame Transmission Processing Function
 *
 * Handles LIN frame transmission based on the given node ID and interrupt status.
 *
 * @param nodeId The node ID
 * @param intSta The interrupt status
 */
static void Lin_FrameTransmitProc(uint8 nodeId, uint32 intSta)
{
    const Lin_Uart      *locNodeCfg;
    Lin_NodeDataType        *locNodeData;
    uint8 coreId = Lin_GetCoreId();

    /* Initialize local variables*/
    locNodeCfg  = &(Lin_Handler[coreId]->config->channels[nodeId]);
    locNodeData = &(Lin_Handler[coreId]->channelInfo[nodeId].nodeData);
    /* get the transmit result */
    if (intSta & LIN_INTR0_APBCMDDONE)
    {
        /* updtae the lin channel status */
        Lin_Handler[coreId]->channelInfo[nodeId].ChannelState = LIN_TX_OK;
        if (locNodeCfg->dataPtr.mode == LIN_UART_SLAVE)
        {
            locNodeData->framestate   = LIN_FRAMEPENDING;
#if (LIN_SLAVE_MODE_USED == STD_ON)
            LinIf_TxConfirmation(nodeId);
#endif /* LIN_SLAVE_MODE_USED */
        }
        else
        {
            locNodeData->framestate   = LIN_FRAMEIDLE;
        }
    }
    else if (intSta & LIN_INTR0_APBCMDABORT)
    {
        /* updtae the lin channel status */
        Lin_Handler[coreId]->channelInfo[nodeId].ChannelState = LIN_TX_ERROR;

        if (locNodeCfg->dataPtr.mode == LIN_UART_SLAVE)
        {
            locNodeData->framestate   = LIN_FRAMEPENDING;
#if (LIN_SLAVE_MODE_USED == STD_ON)
                LinIf_LinErrorIndication(nodeId, LIN_ERR_RESP_DATABIT);
#endif /* LIN_SLAVE_MODE_USED */
        }
        else
        {
            locNodeData->framestate   = LIN_FRAMETRANSMITERR;
        }
    }
}

/**
 * @brief Handles LIN Frame Pending Events
 *
 * Processes LIN frame pending events based on the given node ID and interrupt status.
 *
 * @param nodeId The node ID
 * @param intSta The interrupt status
 */
static void Lin_FramePendingProc(uint8 nodeId, uint32 intSta)
{
    const Lin_Uart      *locNodeCfg;
    Lin_NodeDataType        *locNodeData;
    uint8 coreId = Lin_GetCoreId();

    /* Initialize local variables*/
    locNodeCfg  = &(Lin_Handler[coreId]->config->channels[nodeId]);
    locNodeData = &(Lin_Handler[coreId]->channelInfo[nodeId].nodeData);
    /* get abr check result */
    if (intSta & LIN_INTR0_ABRPASSE)
    {
        Lin_UartClrRxFifo(locNodeCfg);
        return;
    }

    if (intSta & LIN_INTR0_ABRFAILE)
    {
        Lin_UartClrRxFifo(locNodeCfg);
        Lin_Handler[coreId]->channelInfo[nodeId].ChannelState = LIN_RX_ERROR;
        /* When automatic baud rate detection fails, you need to restart the
        module and re-enable automatic baud rate detection. */
        Lin_UartRstMod(locNodeCfg);
        Lin_UartSetAbrEn(locNodeCfg, TRUE);
        return;
    }
    /* get pid check result */
    if ((intSta & LIN_INTR0_RXPIDERR))
    {
#if (LIN_SLAVE_MODE_USED == STD_ON)
        LinIf_LinErrorIndication(nodeId, LIN_ERR_HEADER);
#endif /* LIN_SLAVE_MODE_USED */
        return;
    }

    if ((intSta & LIN_INTR0_RXPIDPASS))
    {
        Lin_PduType slvPduInfo;
        slvPduInfo.Pid = Lin_UartPidGet(locNodeCfg);
        slvPduInfo.SduPtr = locNodeData->txframe;
        slvPduInfo.Cs = LIN_ENHANCED_CS;
        slvPduInfo.Dl = 0;
        slvPduInfo.Drc = LIN_SLAVE_TO_SLAVE;
#if (LIN_SLAVE_MODE_USED == STD_ON)
        Std_ReturnType Ret = E_NOT_OK;
        Ret = LinIf_HeaderIndication(nodeId, &slvPduInfo);
        if (Ret != E_OK || slvPduInfo.Drc == LIN_SLAVE_TO_SLAVE)
        {
            return;
        }
#endif /* LIN_SLAVE_MODE_USED */
        Lin_HwSetNodePdu(locNodeData, &slvPduInfo);
        /* this branch only can be touched in slave mode */
        /* PRQA S 2992,2996,2880  50 */
        if (slvPduInfo.Drc == LIN_MASTER_RESPONSE)
        {
            Lin_UartReceive(locNodeCfg, locNodeData->cs, locNodeData->dl);
            locNodeData->framestate = LIN_FRAMERECEIVE;
            Lin_Handler[coreId]->channelInfo[nodeId].ChannelState = LIN_RX_NO_RESPONSE;
        }
        else if (slvPduInfo.Drc == LIN_SLAVE_RESPONSE)
        {
            Lin_UartTransmit(locNodeCfg, locNodeData->cs, locNodeData->txframe, locNodeData->dl);
            locNodeData->framestate   = LIN_FRAMETRANSMIT;
            Lin_Handler[coreId]->channelInfo[nodeId].ChannelState = LIN_TX_BUSY;
        }
    }
}

/**
 * @brief LIN Active Process Function
 *
 * Executes the corresponding LIN communication activity processing based on the given node ID and interrupt status.
 *
 * @param nodeId The node ID
 * @param intSta The interrupt status
 */
static void Lin_ActiveProcess(uint8 nodeId, uint32 intSta)
{
    Lin_NodeDataType        *locNodeData;
    uint8 coreId = Lin_GetCoreId();

    /* Initialize local variables*/
    locNodeData = &(Lin_Handler[coreId]->channelInfo[nodeId].nodeData);
    switch (locNodeData->framestate)
    {
    case LIN_FRAMERECEIVE:
        Lin_FrameRecieveProc(nodeId, intSta);
        break;
    case LIN_FRAMETRANSMIT:
        Lin_FrameTransmitProc(nodeId, intSta);
        break;
    /* LIN_FRAMEPENDING : slave mode only */
    case LIN_FRAMEPENDING:
        Lin_FramePendingProc(nodeId, intSta);
        break;
    default:
        break;
    }
}

/**
 * @brief Sets the LIN Node PDU
 *
 * Sets the properties of the LIN Node PDU based on the given LIN PDU.
 *
 * @param locNodePdu Pointer to the LIN_NodeData structure, representing the LIN Node PDU
 * @param locPdu Pointer to the LIN_PduType structure, representing the LIN PDU
 */
void Lin_HwSetNodePdu(Lin_NodeDataType *locNodePdu, const Lin_PduType *locPdu)
{
    /* PRQA S 1861,2985 2 */
    locNodePdu->pid = locPdu->Pid | LIN_CALCPARITY1 (locPdu->Pid) | LIN_CALCPARITY2(locPdu->Pid);
    /* PRQA S 2961 15 */
    if (locPdu->Cs == LIN_ENHANCED_CS) {
        locNodePdu->cs = 1;
    } else {
        locNodePdu->cs = 0;
    }

    locNodePdu->drc = (uint8)locPdu->Drc;
    locNodePdu->dl = (uint8)locPdu->Dl;

    /* lin frame data length : 0 - 8 */
    if (locPdu->Dl > 0U && locPdu->SduPtr != NULL_PTR && locPdu->Dl <= 8U) {
        Mcal_MemCpy(locNodePdu->txframe, locPdu->SduPtr, locPdu->Dl);
        Mcal_MemSet(locNodePdu->rxframe, 0, locPdu->Dl);
    }
}

/**
 * @brief Resets the LIN Hardware Module
 *
 * Resets the LIN hardware module based on the given channel ID.
 *
 * @param ChannelID The channel ID
 */
void Lin_HwRstMod(uint8 ChannelID)
{
    uint8 coreId = Lin_GetCoreId();
    const Lin_Uart *locNodeCfg = &(Lin_Handler[coreId]->config->channels[ChannelID]);
    Lin_UartRstMod(locNodeCfg);
}

/**
 * @brief Sends a LIN Frame
 *
 * Sends a LIN frame over the specified channel ID. If the frame is ready, it processes the transmission.
 *
 * @param ChannelID The channel ID
 *
 * @return Returns the operation result, E_OK on success, E_NOT_OK on failure
 */
/* Send 'break field' and filled data frame. */
uint8 Lin_HwSendFrame(uint8 ChannelID)
{
    Std_ReturnType Ret = E_NOT_OK;
    uint8 coreId = Lin_GetCoreId();
    Lin_NodeDataType *locNodeData = &(Lin_Handler[coreId]->channelInfo[ChannelID].nodeData);
    const Lin_Uart *locNodeCfg = &(Lin_Handler[coreId]->config->channels[ChannelID]);

    /* Process the frame for tramssion if ready*/
    if ((locNodeData->currentState == LIN_ACTIVE) && (locNodeData->framestate == LIN_FRAMEIDLE)) {
        locNodeData->framestate = LIN_FRAMETRANSMIT;
        Lin_UartPidSet(locNodeCfg, locNodeData->pid);

        if ((uint8)LIN_MASTER_RESPONSE == locNodeData->drc) {
            Lin_Handler[coreId]->channelInfo[ChannelID].ChannelState = LIN_TX_BUSY;
            Lin_UartTransmit(locNodeCfg, locNodeData->cs, locNodeData->txframe, locNodeData->dl);
        } else if ((uint8)LIN_SLAVE_RESPONSE == locNodeData->drc) {
            locNodeData->framestate = LIN_FRAMERECEIVE;
            Lin_Handler[coreId]->channelInfo[ChannelID].ChannelState = LIN_RX_NO_RESPONSE;
            Lin_UartReceive(locNodeCfg, locNodeData->cs, locNodeData->dl);
        }

        Ret = E_OK;
    }

    return Ret;
}

/**
 * @brief Lin_TransmitCallBk Function
 *
 * This is a callback function used to handle LIN transmission-related events.
 *
 * @param numNodeID The node ID
 */
void Lin_TransmitCallBk(uint8 numNodeID)
{
    const Lin_Uart      *locNodeCfg;
    Lin_NodeDataType        *locNodeData;
    boolean chanErr = FALSE;
    uint8 coreId = Lin_GetCoreId();

    /* Initialize local variables*/
    locNodeCfg  = &(Lin_Handler[coreId]->config->channels[numNodeID]);
    locNodeData = &(Lin_Handler[coreId]->channelInfo[numNodeID].nodeData);

    uint32 int_sta = Lin_UartGetInt(locNodeCfg);
    Lin_UartClearInt(locNodeCfg, int_sta);
    /* check err interrupt first */
    if (locNodeData->currentState != LIN_WAIT_FOR_WAKEUP) {
        chanErr = Lin_CheckChanErrsta(numNodeID, int_sta);
        if (TRUE == chanErr)
        {
            return;
        }

    }

    switch (locNodeData->currentState) {
    case LIN_WAIT_FOR_WAKEUP:
        Lin_WakeupProcess(numNodeID, int_sta);
        break;
    case LIN_ACTIVE:
        Lin_ActiveProcess(numNodeID, int_sta);
        break;
    default:
        break;
    }
}

#define LIN_STOP_SEC_CODE_FAST
#include "Lin_MemMap.h"

#define LIN_START_SEC_CODE
#include "Lin_MemMap.h"
/**
 * @brief Initialize LIN Node
 *
 * Initializes the LIN node based on the given node ID.
 *
 * @param numNodeId The node ID
 *
 * @return Std_ReturnType The result of initialization, E_OK on success
 */
Std_ReturnType Lin_NodeInit(uint8 numNodeId)
{
    const Lin_Uart *locNodeCfg;
    Lin_ChannelInfoType *locNodeData;
    uint8 coreId = Lin_GetCoreId();

    locNodeCfg = &Lin_Handler[coreId]->config->channels[numNodeId];
    locNodeData = &Lin_Handler[coreId]->channelInfo[numNodeId];

    if (locNodeCfg->dataPtr.mode == LIN_UART_MASTER) {
        locNodeData->nodeData.framestate = LIN_FRAMEIDLE;
    } else {
        locNodeData->nodeData.framestate = LIN_FRAMEPENDING;
    }

    locNodeData->nodeData.currentState = LIN_WAIT_FOR_WAKEUP;
    locNodeData->nodeData.error = LIN_OK;
    Lin_UartInit(locNodeCfg);

    return E_OK;
}

/**
 * @brief Wakeup LIN Hardware
 *
 * Wakeup the LIN hardware through the specified node ID.
 *
 * @param numNodeId The node ID
 */
void Lin_HwWakeup(uint8 numNodeId)
{
    const Lin_Uart     *locNodeCfg;
    uint8 coreId = Lin_GetCoreId();

    locNodeCfg = &Lin_Handler[coreId]->config->channels[numNodeId];
    Lin_Uart_Set_Break(locNodeCfg);
}

/**
 * @brief Get LIN Hardware Node
 *
 * Retrieves the corresponding LIN hardware node based on the given LIN base address.
 *
 * @param LinBaseAddr The LIN base address
 *
 * @return Returns the corresponding LIN hardware node ID. If not found, returns LIN_NUM_CHANNELS + 1.
 */
uint32 Lin_HwGetNode(uint32 LinBaseAddr)
{
    const Lin_Uart     *locNodeCfg;
    uint32 NodeId;
    uint8 coreId = Lin_GetCoreId();

    for (NodeId = 0; NodeId < Lin_Handler[coreId]->config->numberOfNodes; NodeId++) {
        locNodeCfg = &Lin_Handler[coreId]->config->channels[NodeId];

        if (locNodeCfg->linModuleBase == LinBaseAddr) {
            break;
        }
    }

    return NodeId;
}

#define LIN_STOP_SEC_CODE
#include "Lin_MemMap.h"

#ifdef __cplusplus
}
#endif
